use std::ops;

use super::Matrix;

impl Matrix<f64> {
    pub fn shape(&self) -> (usize, usize) {
        (self._row, self._col)
    }

    pub fn row(&self) -> usize {
        self._row
    }

    pub fn col(&self) -> usize {
        self._col
    }
}

impl ops::Index<(isize, isize)> for Matrix<f64> {
    type Output = f64;

    fn index(&self, index: (isize, isize)) -> &Self::Output {
        let r: usize = if index.0 < 0 {
            self._row - index.0 as usize
        } else {
            index.0 as usize
        };
        let c: usize = if index.1 < 0 {
            self._col - index.1 as usize
        } else {
            index.1 as usize
        };

        &self.data[r][c]
    }
}

impl ops::Index<isize> for Matrix<f64> {
    type Output = Vec<f64>;

    fn index(&self, index: isize) -> &Self::Output {
        let r: usize = if index < 0 {
            self._row - index as usize
        } else {
            index as usize
        };
        &self.data[r]
    }
}

impl ops::IndexMut<(isize, isize)> for Matrix<f64> {
    fn index_mut(&mut self, index: (isize, isize)) -> &mut Self::Output {
        let r: usize = if index.0 < 0 {
            self._row - index.0 as usize
        } else {
            index.0 as usize
        };
        let c: usize = if index.1 < 0 {
            self._col - index.1 as usize
        } else {
            index.1 as usize
        };
        &mut self.data[r][c]
    }
}

impl ops::IndexMut<isize> for Matrix<f64> {
    fn index_mut(&mut self, index: isize) -> &mut Self::Output {
        let r: usize = if index < 0 {
            self._row - index as usize
        } else {
            index as usize
        };

        &mut self.data[r]
    }
}
